
module Schnell
  class InputElement < Element    
    # return the type of the element
    def_wrap_guard :type # input elements only        
  end

  class Button < InputElement
    ELEMENT_TYPE = "input"
    INPUT_TYPES = ["button","image","submit"]
  end
  
  class TextInputElement < InputElement
    
    #returns true if text field is read only
    def readonly?
      assert_exists
      begin
        assert_enabled
      rescue ObjectReadOnlyException,ObjectDisabledException => ex
        return true if ex.is_a?(ObjectReadOnlyException)
      end
      return false
    end
        
    #verfies the content of text field. Returns true if the content matches
    def verify_contains(expected_value)
      assert_exists
      return true if @element.getValue.eql? expected_value      
      return false
    end
    
    # adds text to the text already existing in text field
    def append(text)
      assert_enabled
      @element.sendKeys(text.split('').to_java(:String))
    end    
    
    #returns the contents of the text field
    def getContents
      assert_exists
      return @element.getValue
    end 

    #sets the text in the active text field
    def set(text)
      assert_exists
      assert_enabled
      @element.clear
      @element.sendKeys(text.split('').to_java(:String))
    end
    
    #clears the contents of the text field
    def clear
      assert_enabled
      @element.clear()
    end   
  end
  
  class TextField < TextInputElement
    ELEMENT_TYPE = "input"
    INPUT_TYPES = ["text","password"]
    
    # Todo - To work on the after text and before text
    def locate
      if @how == :beforeText
        elements = @page.findElementsByXPath("//#{self.class::ELEMENT_TYPE}")
        if (defined? self.class::INPUT_TYPES)
          elements = elements.select { |field| (self.class::INPUT_TYPES).include?(field.getAttribute("type"))}
        end
        @selected_fields = elements.select{|field| field.send("getElement").getPreviousSibling.getText.strip!.eql?(@what)}
        @element = @selected_fields[0]
      elsif @how == :afterText
        elements = @page.findElementsByXPath("//#{self.class::ELEMENT_TYPE}")
        if (defined? self.class::INPUT_TYPES)
          elements = elements.select { |field| (self.class::INPUT_TYPES).include?(field.getAttribute("type"))}
        end
        @selected_fields = elements.select{|field| field.send("getElement").getNextSibling.getText.strip!.eql?(@what)}
        @element = @selected_fields[0]        
      else
        super()
      end
    end
    
    private :locate
    
    #drags text from one text field to another
    def dragContentsTo(how,what)
      assert_enabled
      element_from = @element
      @how, @what = how, what
      assert_enabled
      element_to = @element
      value = element_from.getValue
      element_from.clear
      element_to.sendKeys(value.split('').to_java(:String))
    end
  end
  
  class RadioCheckCommon < InputElement
    ELEMENT_TYPE = "input"
    
    #select the checkbox or radio button
    def set(checked = true)
      assert_exists
      assert_enabled
      @element.setChecked(checked)
    end
    
    #clear the checkbox or radio button
    def clear
      assert_exists
      assert_enabled
      @element.setChecked(false)
    end
    
    #returns true if the checkbox or radio button
    def isSet?
      assert_exists
      return @element.isChecked
    end
    alias getState isSet?
    alias checked? isSet?        
  end
  
  class CheckBox < RadioCheckCommon
    INPUT_TYPES = ["checkbox"]
  end
  
  class Radio < RadioCheckCommon
    INPUT_TYPES = ["radio"]
  end
  
  class SelectList < InputElement
    ELEMENT_TYPE = "select"
    
    #returns the options available in select box
    def items
      assert_exists
      return @element.getOptions.collect{|element| element.asText}
    end
    
    #returns true if option is available in the select box
    def includes?(value)
      assert_exists
      options = self.items
      return options.include?(value)
    end
    
    #returns the number of options in the select box
    def length
      assert_exists
      return @element.getOptionSize
    end
    
    #selects the option in the select box
    def select(option)
      assert_exists
      assert_enabled
      
      if option.is_a?(String)
        value = option
      elsif option.is_a?(Integer)
        value = self.items[option - 1]
      end
      select_option = self.getOptionfromValues(value)
      @element.setSelectedAttribute(select_option,true)      
    end
    
    #selects the option according to the value given
    def select_value(value)
      assert_exists
      assert_enabled
      raise NoValueFoundException if not (@element.getOptions.collect{|option| option.getValueAttribute}).include? value
      @element.setSelectedAttribute(value,true)
    end
    
    #returns the options selected in a select box
    def getSelectedItems
      assert_exists
      return @element.getSelectedOptions.collect {|element| element.asText}
    end
    
    #deselects the options selected in a select box
    def clearSelection
      assert_exists
      assert_enabled
      selected_items = @element.getSelectedOptions
      selected_items.each{|item| @element.setSelectedAttribute(item,false)}
    end
    
    #returns the value of the option selected in the select box
    def value
      assert_exists
      return @element.getSelectedOptions[0].getValueAttribute
    end
    
    #returns the type of select box, if it is single select or multiple select box
    def type
      assert_exists
      return "select-multiple" if @element.hasAttribute("multiple")
      return "select-one"
    end
    
    protected
    def getOptionfromValues(value)
      assert_exists
      select_values = self.items
      index = select_values.index(value)
      raise NoValueFoundException if index.nil?
      return @element.getOption(index)
    end
  end
  class TextArea < TextInputElement
    ELEMENT_TYPE = "textarea"
  end
  
  class Hidden < TextInputElement
    ELEMENT_TYPE = "input"
    INPUT_TYPES = ["hidden"]
  end
end